package org.jeecg.modules.htxincailiao.account.controller;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.tips.ErrorTip;
import org.jeecg.common.util.*;
import org.jeecg.common.util.RequestUtil;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.htxincailiao.account.constant.HTAccountTypeEnum;
import org.jeecg.modules.htxincailiao.account.domain.bo.*;
import org.jeecg.modules.htxincailiao.account.domain.dto.*;
import org.jeecg.modules.htxincailiao.account.domain.vo.HTUserInfoVO;
import org.jeecg.modules.htxincailiao.account.domain.vo.HTUserStatisticsVO;
import org.jeecg.modules.htxincailiao.account.entity.*;
import org.jeecg.modules.htxincailiao.account.service.*;
import org.jeecg.modules.vendors.tencent.account.entity.HTTencentAccount;
import org.jeecg.modules.vendors.tencent.account.service.IHTTencentAccountService;
import org.jeecg.modules.vendors.tencent.official_account.entity.auth.OfficialAccountQrcode;
//import org.jeecg.modules.vendors.tencent.util.MD5Utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;

import static org.jeecg.common.util.SmartVerificationUtil.PHONE_REGEXP;

/**
 * @Description: ht_account
 * @Author: jeecg-boot
 * @Date: 2021-05-25
 * @Version: V1.0
 */
@Api(tags = "ht_account")
@RestController
@RequestMapping("/account/")
@Slf4j
public class HTAccountController {

    @Resource
    private RedisUtil redisUtil;


    @Resource
    private JeecgBaseConfig jeecgBaseConfig;
    @Resource
    private IHTForumsExpertService forumsExpertService;

    @Resource
    private IHTMerchantService merchantService;

    @Resource
    private IHTEvaluationAgencyService evaluationAgencyService;

    @Resource
    private IHTAllianceService allianceService;

    @Resource
    private IHTAllianceMemberService allianceMemberService;

    @Resource
    private IHTAccountService accountService;

    @Resource
    private IHTTencentAccountService tencentAccountService;

    @Resource
    private BaseCommonService baseCommonService;

    /**
     * 用户登录操作
     *
     * @return 返回用户信息
     */
    @PostMapping(value = "guestSignIn")
    @ApiOperation(value = "访客登录", produces = "application/json")
    public Result<JSONObject> guestSignIn(@RequestBody @Valid HTGuestAuthDTO dto) {
        Result<JSONObject> result = new Result<JSONObject>();
        String username = dto.getUsername().trim();
        //1. 通过登录账号、手机号查询用户
        HTPlatformUser user = accountService.queryFrontendUserByUsername(username);
        if (oConvertUtils.isEmpty(user)) {
            result.error500("访客不存在");
            return result;
        }

        String storedPassword = null;
        if (oConvertUtils.isEmpty(user)) {
            result.error500("该用户不存在，请先进行注册");
        } else {
            storedPassword = user.getPassword();

            String token = addOrUpdateToken(user.getUsername(), storedPassword);
            JSONObject obj = new JSONObject();

            //添加日志
            baseCommonService.addLog("用户名: " + username + ",登录成功！", CommonConstant.LOG_TYPE_1, null);

            obj.put("token", token);
            if (oConvertUtils.isNotEmpty(user)) {
                obj.put("userInfo", user);
            }
            result.setResult(obj);
            result.success("登录成功");
        }
        return result;
    }

    /**
     * 用户登录操作
     *
     * @return 返回用户信息
     */
    @PostMapping(value = "signInWithPassword")
    @ApiOperation(value = "门户登录", produces = "application/json")
    public Result<JSONObject> signInWithPassword(@RequestBody @Valid HTAccountAuthDTO dto) {
        Result<JSONObject> result = new Result<JSONObject>();
        String username = dto.getUsername().trim();
        String password = dto.getPassword().trim();
        String captcha = dto.getCaptcha().trim();
        String phoneNumber = null;
        boolean matches = Pattern.matches(PHONE_REGEXP, username);
        if (matches) {
            phoneNumber = username;
        }

//        LimitSignInAttempts.ResetAttemptsInfo(redisUtil, phoneNumber, username);
        LimitSignInAttempts attempts = LimitSignInAttempts.CheckFailedLock(redisUtil, phoneNumber, username, result);
        if (attempts.isLocked()) {
            return attempts.getResult();
        }

        String lowerCaseCaptcha = captcha.toLowerCase();
        String origin = lowerCaseCaptcha + dto.getCaptchaCheckKey() + jeecgBaseConfig.getSignatureSecret();
        String realKey = Md5Util.md5Encode(origin, "utf-8");
//        String realKey = Md5Util.md5Encode(lowerCaseCaptcha + dto.getCaptchaCheckKey(), "utf-8");
        Object checkCode = redisUtil.get(realKey);
//        log.info("\n\n\n checkCode = {}  lowerCaseCaptcha = {}\n\n\n", checkCode, lowerCaseCaptcha);

        if (checkCode == null || !checkCode.toString().equals(lowerCaseCaptcha)) {
            LimitSignInAttempts failedAttempts = LimitSignInAttempts.HandleFailedAttempts(redisUtil, phoneNumber, username, result);
            if (failedAttempts.isLocked()) {
                return failedAttempts.getResult();
            } else {
                result.error500("验证码错误");
                return result;
            }
        }

        //1. 通过登录账号、手机号查询用户
        HTPlatformUser user = null;
        if (oConvertUtils.isNotEmpty(phoneNumber)) {
            user = accountService.queryFrontendUserByPhoneNumber(phoneNumber);
        } else {
            user = accountService.queryFrontendUserByUsername(username);
        }

        String storedPassword = null;
        Object userInfo = null;
        if (oConvertUtils.isEmpty(user)) {
            result.error500("该用户不存在，请先进行注册");
        } else {
            storedPassword = user.getPassword();
            if (oConvertUtils.isEmpty(storedPassword)) {
                result.error500("未设置密码，请通过短信验证码登录");
                return result;
            }
            userInfo = user;

            //2. 校验用户名或密码是否正确
            if (!storedPassword.equals(password)) {
                LimitSignInAttempts failedAttempts = LimitSignInAttempts.HandleFailedAttempts(redisUtil, phoneNumber, username, result);
                if (failedAttempts.isLocked()) {
                    return failedAttempts.getResult();
                } else {
                    result.error500("密码错误");
                    return result;
                }
            }

            String token = addOrUpdateToken(user.getUsername(), storedPassword);
            LimitSignInAttempts.ResetAttemptsInfo(redisUtil, phoneNumber, username);
            JSONObject obj = new JSONObject();

            //添加日志
            baseCommonService.addLog("用户名: " + username + ",登录成功！", CommonConstant.LOG_TYPE_1, null);

            obj.put("token", token);
            if (oConvertUtils.isNotEmpty(user)) {
                HTAccountTypeEnum accountTypeEnum = HTAccountTypeEnum.values()[user.getAccountType()];
                HTUserInfoVO userInfoVO = accountService.getUserInfo(accountTypeEnum, user.getId());
                if (oConvertUtils.isNotEmpty(userInfoVO)) {
                    obj.put("userInfo", userInfoVO);
                } else {
                    obj.put("userInfo", user);
                }
            }
            result.setResult(obj);
            result.success("登录成功");
        }
        return result;
    }

    /**
     * 短信验证码登录
     *
     * @param dto
     * @return
     */
    @PostMapping(value = "signInWithSMSCaptcha")
    public Result<JSONObject> signInWithSMSCaptcha(@Valid @RequestBody HTSignInSMSCaptchaDTO dto) {
        Result<JSONObject> result = new Result<>();

        String phoneNumber = dto.getPhoneNumber();
        String cachedCaptcha = (String) redisUtil.get(phoneNumber);
        String requestCaptcha = dto.getCaptcha();

        if (oConvertUtils.isEmpty(requestCaptcha)) {
            result.error500("验证码不能为空");
        } else if (!requestCaptcha.equals(cachedCaptcha)) {
            LimitSignInAttempts failedAttempts = LimitSignInAttempts.HandleFailedAttempts(redisUtil, phoneNumber, null, result);
            if (failedAttempts.isLocked()) {
                return failedAttempts.getResult();
            } else {
                result.error500("验证码错误");
                return result;
            }
        } else if (oConvertUtils.isEmpty(cachedCaptcha)) {
            result.error500("验证码失效");
        } else {
            String tempPassword = UUIDGenerator.generate();
            boolean isAccountExist = accountService.validateAccountExistByMultipleFactor(null, phoneNumber, null);
            if (isAccountExist) {
                HTPlatformUser user = accountService.queryFrontendUserByPhoneNumber(phoneNumber);
                String username = oConvertUtils.isNotEmpty(user.getUsername()) ? user.getUsername() : phoneNumber;
                String token = addOrUpdateToken(username, tempPassword);
                JSONObject obj = new JSONObject();

                //添加日志
                baseCommonService.addLog("用户名: " + username + ",登录成功！", CommonConstant.LOG_TYPE_1, null);

                obj.put("token", token);

                if (oConvertUtils.isNotEmpty(user)) {
                    HTAccountTypeEnum accountTypeEnum = HTAccountTypeEnum.values()[user.getAccountType()];
                    HTUserInfoVO userInfoVO = accountService.getUserInfo(accountTypeEnum, user.getId());
                    if (oConvertUtils.isNotEmpty(userInfoVO)) {
                        obj.put("userInfo", userInfoVO);
                    } else {
                        obj.put("userInfo", user);
                    }
                }
                result.setResult(obj);
                result.setCode(200);
            } else {
                result.error500("用户不存在！");
            }
        }

        return result;
    }


    /**
     * 退出登录
     *
     * @param request  vc
     * @param response
     * @return
     */
    @RequestMapping(value = "/signOut")
    public Result<Object> logout(HttpServletRequest request, HttpServletResponse response) {
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        String username = JwtUtil.getUsername(token);
        HTPlatformUser user = null;
        if (oConvertUtils.isNotEmpty(username)) {
            user = accountService.queryFrontendUserByUsername(username);
        }

        if (user != null) {
            deleteUserCache(token, user.getId(), user.getUsername());
            return Result.OK("退出登录成功！");
        }

        return Result.OK("退出登录成功！");
    }

    private String addOrUpdateToken(String username, String password) {
        String token = JwtUtil.sign(username, password);
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
        return token;
    }

    private void deleteUserCache(String token, String userId, String username) {
        //清空用户登录Token缓存
        redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
        //清空用户登录Shiro权限缓存
        redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + userId);
        //清空用户的缓存信息（包括部门信息），例如sys:cache:user::<username>
        redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, username));
        //调用shiro的logout
        SecurityUtils.getSubject().logout();
    }

    /**
     * 短信验证码注册
     *
     * @param dto 短信验证码dto
     * @return 注册结果
     */
    @PostMapping(value = "signUpWithSMSCaptcha")
    public Result<JSONObject> signUpWithSMSCaptcha(@Valid @RequestBody HTSignUpSMSCaptchaDTO dto) {
        Result<JSONObject> result = new Result<>();

        switch (dto.getAccountType()) {
            case MERCHANT:
                if (oConvertUtils.isEmpty(dto.getContactPerson())) {
                    result.error500("联系人不能为空");
                    return result;
                }

                if (oConvertUtils.isEmpty(dto.getEnterpriseName())) {
                    result.error500("企业名称不能为空");
                    return result;
                }
                break;
            default:
                if (oConvertUtils.isEmpty(dto.getRealName())) {
                    result.error500("姓名不能为空");
                    return result;
                }
                break;
        }

        String phoneNumber = dto.getPhoneNumber();
        boolean isAccountExist = accountService.validateAccountExistByMultipleFactor(null, phoneNumber, null);
        if (isAccountExist) {
            result.error500("用户已注册, 请重新登录");
        } else {
            boolean succeed = false;
            String cachedCaptcha = (String) redisUtil.get(phoneNumber);
            String requestCaptcha = dto.getCaptcha();

            if (oConvertUtils.isEmpty(requestCaptcha)) {
                result.error500("验证码不能为空");
            } else if (!requestCaptcha.equals(cachedCaptcha)) {
                result.error500("验证码错误");
            } else if (oConvertUtils.isEmpty(cachedCaptcha)) {
                result.error500("验证码失效");
            } else {
                HTAccountAddBO bo = SmartBeanUtil.copy(dto, HTAccountAddBO.class);
                bo.setUsername(phoneNumber);

                //手机验证码注册默认普通用户类型
                String tempPassword = UUIDGenerator.generate();
                switch (dto.getAccountType()) {
                    case MERCHANT:
                        succeed = accountService.handleSignUpForMerchant(bo);
                        break;
                    default:
                        succeed = accountService.handleSignUpForMember(bo);
                        break;
                }

                if (succeed) {
                    String token = addOrUpdateToken(phoneNumber, tempPassword);
                    JSONObject obj = new JSONObject();

                    obj.put("token", token);

                    result.setResult(obj);
                } else {
                    result.error500("注册失败！");
                }
            }
        }

        return result;
    }

    /**
     * 产业服务 会议会展沙龙短信验证码签到 （未注册用户会自动签到）
     *
     * @param dto 签到dto
     * @return 签到注册结果
     */
    @PostMapping(value = "checkInWithSMSCaptcha")
    public Result<JSONObject> checkInWithSMSCaptcha(@Valid @RequestBody HTCheckInSMSCaptchaDTO dto) {
        Result<JSONObject> result = new Result<>();
        if (dto.getAccountType().equals(HTAccountTypeEnum.MERCHANT)) {
            if (oConvertUtils.isEmpty(dto.getEnterpriseName())) {
                result.error500("企业名称不能为空");
                return result;
            }
        }

        if (oConvertUtils.isEmpty(dto.getParticipant())) {
            result.error500("参会人员不能为空");
            return result;
        }

        String phoneNumber = dto.getPhoneNumber();
        boolean isAccountExist = accountService.validateAccountExistByMultipleFactor(null, phoneNumber, null);
        //手机验证码注册默认普通用户类型
        String tempPassword = UUIDGenerator.generate();

        if (isAccountExist) {
            HTPlatformUser user = accountService.queryFrontendUserByPhoneNumber(phoneNumber);
            String username = user.getUsername();
            if (oConvertUtils.isNotEmpty(user.getPassword())) {
                tempPassword = user.getPassword();
            }
            String token = addOrUpdateToken(username, tempPassword);
            JSONObject obj = new JSONObject();

            obj.put("token", token);

            result.setResult(obj);
        } else {
            boolean succeed = false;
            String cachedCaptcha = (String) redisUtil.get(phoneNumber);
            String requestCaptcha = dto.getCaptcha();

            if (oConvertUtils.isEmpty(requestCaptcha)) {
                result.error500("验证码不能为空");
            } else if (!requestCaptcha.equals(cachedCaptcha)) {
                result.error500("验证码错误");
            } else if (oConvertUtils.isEmpty(cachedCaptcha)) {
                result.error500("验证码失效");
            } else {
                HTAccountAddBO bo = SmartBeanUtil.copy(dto, HTAccountAddBO.class);
                bo.setUsername(phoneNumber);

                if (dto.getAccountType() == HTAccountTypeEnum.MERCHANT) {
                    bo.setContactPerson(dto.getParticipant());
                    succeed = accountService.handleSignUpForMerchant(bo);
                } else {
                    bo.setRealName(dto.getParticipant());
                    succeed = accountService.handleSignUpForMember(bo);
                }

                if (succeed) {
                    String token = addOrUpdateToken(phoneNumber, tempPassword);
                    JSONObject obj = new JSONObject();

                    obj.put("token", token);

                    result.setResult(obj);
                } else {
                    result.error500("注册失败！");
                }
            }
        }

        return result;
    }

    private HTTencentAccount getTencentAccountByUser(HTPlatformUser user) {
        HTTencentAccount tencentAccount = tencentAccountService.queryByUserId(user.getId());

        //已经与平台产生过交互的用户
        if (Objects.isNull(tencentAccount)) {
            //1 是否从未关注
            tencentAccount = new HTTencentAccount();
            tencentAccount.setUserId(user.getId());
            try {
                tencentAccountService.save(tencentAccount);
                if (!accountService.bindTencentAccountBy(user)) {
                    throw new JeecgBootException("绑定腾讯账户失败");
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new JeecgBootException("创建腾讯平台账户失败！");
            }
        }

        return tencentAccount;
    }

    private void handOfficialAccountBindInfo(HTTencentAccount tencentAccount, HTPlatformUser user, JSONObject resultObj) {
        //公众号绑定状态 0-从未绑定 1-已绑定 2-绑定后取消, 只有未绑定的情况下才生成二维码
        if (tencentAccount.getOfficialAccountBindStatus() != 1) {
            try {
                String sceneStr = user.getId();
                OfficialAccountQrcode officialAccountQrcode = OfficialAccountQrcode.createQrcode(sceneStr, this.redisUtil);
                resultObj.put("qrcodeUrl", officialAccountQrcode.getQrcodeUrl());
                resultObj.put("sceneStr", sceneStr);
                resultObj.put("officialAccountBindStatus", tencentAccount.getOfficialAccountBindStatus());
            } catch (Exception e) {
                e.printStackTrace();
                throw new JeecgBootException("创建二维码失败！");
            }
        } else {
            //已绑定用户直接返回相关信息无效走二维码流程
            resultObj.put("qrcodeUrl", "");
            resultObj.put("sceneStr", "");
        }
    }

    /**
     * 获取公众号绑定信息
     *
     * @param request 请求体
     * @return 绑定结果
     */
    @Transactional()
    @PostMapping(value = "/getOfficialAccountBindInfo")
    public Result<JSONObject> getOfficialAccountBindInfo(HttpServletRequest request) {
        Result<JSONObject> result = new Result<JSONObject>();
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        JSONObject resultObj = new JSONObject();
        //已登录
        if (oConvertUtils.isNotEmpty(token)) {
            String username = JwtUtil.getUsername(token);
            HTPlatformUser user = accountService.queryFrontendUserByUsername(username);
            if (oConvertUtils.isNotEmpty(user)) {
                HTTencentAccount tencentAccount = getTencentAccountByUser(user);
                resultObj.put("isSignedIn", true);
                handOfficialAccountBindInfo(tencentAccount, user, resultObj);
            } else {
                result.error500("用户不存在");
            }
        } else {
            resultObj.put("isSignedIn", false);
        }

        result.setResult(resultObj);

        return result;
    }

    /**
     * 验证用户是否已注册
     *
     * @param dto 用户名dto
     * @return 验证结果
     */
    @PostMapping(value = "/validateUsername")
    public Result<JSONObject> validateUsername(@RequestBody HTValidateUsernameDTO dto) {
        Result<JSONObject> result = new Result<JSONObject>();
        try {
            String username = dto.getUsername();
            HTPlatformUser user = accountService.queryFrontendUserByUsername(username);

            boolean isSignedUp = user != null;
            JSONObject obj = new JSONObject();
            obj.put("isSignedUp", isSignedUp);

            result.setResult(obj);

        } catch (Exception e) {
            e.printStackTrace();
            result.error500(ErrorTip.bzError);
        }

        return result;
    }

    /**
     * @param dto
     * @return
     */
    @PostMapping(value = "/validatePhoneNumber")
    public Result<JSONObject> validatePhoneNumber(@Valid @RequestBody HTValidatePhoneNumberDTO dto) {
        Result<JSONObject> result = new Result<JSONObject>();

        HTPlatformUser user = accountService.queryFrontendUserByPhoneNumber(dto.getPhoneNumber());

        try {
            boolean isSignedUp = oConvertUtils.isNotEmpty(user);
            JSONObject obj = new JSONObject();
            obj.put("isSignedUp", isSignedUp);

            result.setResult(obj);

        } catch (Exception e) {
            e.printStackTrace();
            result.error500(ErrorTip.bzError);
        }

        return result;
    }

    /**
     * @param dto
     * @return
     */
    @PostMapping(value = "/validateEmail")
    public Result<JSONObject> validatePhoneNumber(@Valid @RequestBody HTValidateEmailDTO dto) {
        Result<JSONObject> result = new Result<JSONObject>();

        HTPlatformUser user = accountService.queryFrontendUserByEmail(dto.getEmail());

        try {
            boolean isSignedUp = oConvertUtils.isNotEmpty(user);
            JSONObject obj = new JSONObject();
            obj.put("isSignedUp", isSignedUp);

            result.setResult(obj);

        } catch (Exception e) {
            e.printStackTrace();
            result.error500(ErrorTip.bzError);
        }

        return result;
    }

    /**
     * @param dto
     * @return
     */
    @PostMapping(value = "/validateResetPasswordCaptcha")
    public Result<JSONObject> validateResetPasswordCaptcha(@Valid @RequestBody HTResetPasswordCaptchaDTO dto) {
        Result<JSONObject> result = new Result<JSONObject>();

        String cachedCaptcha = (String) redisUtil.get(dto.getPhoneNumber());
        String requestCaptcha = dto.getCaptcha();
        if (StrUtil.isBlank(cachedCaptcha)) {
            result.error500("验证码失效");
        } else if (!requestCaptcha.equals(cachedCaptcha)) {
            result.error500("验证码错误");
        } else {
            JSONObject obj = new JSONObject();
            obj.put("isValidated", true);
            result.setResult(obj);
        }

        return result;
    }


    /**
     * @param dto 重置密码 修改密码
     * @return 重置结果
     */
    @PostMapping(value = "resetPassword")
    public Result<JSONObject> resetPassword(HttpServletRequest request, @Valid @RequestBody HTResetPasswordDTO dto) {
        Result<JSONObject> result = new Result<>();

        HTResetPasswordBO bo = SmartBeanUtil.copy(dto, HTResetPasswordBO.class);
        boolean succeed = accountService.resetPassword(bo);

        if (succeed) {
            JSONObject obj = new JSONObject();
            obj.put("isRested", true);

            String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
            if (oConvertUtils.isNotEmpty(token)) {
                String username = JwtUtil.getUsername(token);
                HTPlatformUser user = accountService.queryFrontendUserByUsername(username);
                deleteUserCache(token, user.getId(), username);
                String newToken = addOrUpdateToken(user.getUsername(), user.getPassword());
                obj.put("token", newToken);
            }

            result.setResult(obj);
        } else {
            result.error500("操作失败");
        }

        return result;
    }

    /**
     * @param dto
     * @return
     */
    @PostMapping(value = "/validatePhoneNumberCaptcha")
    public Result<JSONObject> validatePhoneNumberCaptcha(@Valid @RequestBody HTResetPasswordCaptchaDTO dto) {
        Result<JSONObject> result = new Result<JSONObject>();

        String cachedCaptcha = (String) redisUtil.get(dto.getPhoneNumber());
        String requestCaptcha = dto.getCaptcha();
        if (StrUtil.isBlank(cachedCaptcha)) {
            result.error500("验证码失效");
        } else if (!requestCaptcha.equals(cachedCaptcha)) {
            result.error500("验证码错误");
        } else {
            JSONObject obj = new JSONObject();
            obj.put("isValidated", true);
            result.setResult(obj);
        }

        return result;
    }

    /**
     * @param dto 修改手机号
     * @return 返回修改手机号的结果
     */
    @PostMapping(value = "editPhoneNumber")
    public Result<JSONObject> editPhoneNumber(HttpServletRequest request, @Valid @RequestBody HTEditPhoneNumberDTO dto) {
        Result<JSONObject> result = new Result<>();
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (oConvertUtils.isNotEmpty(token)) {
            String phoneNumber = dto.getPhoneNumber();
            String cachedCaptcha = (String) redisUtil.get(phoneNumber);
            String requestCaptcha = dto.getCaptcha();

            if (oConvertUtils.isEmpty(requestCaptcha)) {
                result.error500("验证码不能为空");
            } else if (!requestCaptcha.equals(cachedCaptcha)) {
                result.error500("验证码不正确");
            } else if (oConvertUtils.isEmpty(cachedCaptcha)) {
                result.error500("验证码失效");
            } else {
                HTEditPhoneNumberBO bo = SmartBeanUtil.copy(dto, HTEditPhoneNumberBO.class);
                String username = JwtUtil.getUsername(token);
                HTPlatformUser user = accountService.queryFrontendUserByUsername(username);
                boolean succeed = accountService.editPhoneNumber(bo, user);
                if (succeed) {
                    JSONObject obj = new JSONObject();
                    obj.put("edited", true);
                    result.setResult(obj);
                } else {
                    result.error500("编辑手机号失败");
                }
            }
        } else {
            result.error500("请先登录");
        }
        return result;
    }

    /**
     * @param dto 提交资质文件
     * @return 返回修改手机号的结果
     */
    @PostMapping(value = "certificateSubmit")
    public Result<JSONObject> certificateSubmit(HttpServletRequest request, @Valid @RequestBody HTCertificateSubmitDTO dto) {
        Result<JSONObject> result = new Result<>();
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (oConvertUtils.isNotEmpty(token)) {
            HTCertificateSubmitBO certificateAuditBO = SmartBeanUtil.copy(dto, HTCertificateSubmitBO.class);
            boolean succeed = accountService.certificateSubmit(certificateAuditBO);
            if (!succeed) {
                result.error500("操作失败");
            }
        } else {
            result.error500("请先登录");
        }
        return result;
    }

    /**
     * @param dto 审核
     * @return 返回修改手机号的结果
     */
    @PostMapping(value = "certificateAudit")
    public Result<JSONObject> certificateAudit(HttpServletRequest request, @Valid @RequestBody HTUserUpdateDTO dto) {
        Result<JSONObject> result = new Result<>();
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (oConvertUtils.isNotEmpty(token)) {
            HTUserUpdateBO certificateAuditBO = SmartBeanUtil.copy(dto, HTUserUpdateBO.class);
            boolean succeed = accountService.certificateAudit(certificateAuditBO);
            if (!succeed) {
                result.error500("操作失败");
            }
        } else {
            result.error500("请先登录");
        }
        return result;
    }

    /**
     * 待审核列表
     *
     * @param @param request
     * @return Result
     * @throws
     * @Title: cart
     * @Description: 返回待审核列表
     */
    @RequestMapping(value = "/certificateAudit/list", method = {RequestMethod.GET, RequestMethod.POST})
    public Result<?> certificateAuditList(HTPlatformUser user, HttpServletRequest req, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
        if (req.getMethod().equals("POST")) {
            String line = RequestUtil.getPostParam(req);
            if (oConvertUtils.isNotEmpty(line)) {
                user = JSONObject.parseObject(line, HTPlatformUser.class);
                pageNo = oConvertUtils.isNotEmpty(user.getPageNo()) ? user.getPageNo() : pageNo;
                pageSize = oConvertUtils.isNotEmpty(user.getPageSize()) ? user.getPageSize() : pageSize;
            }
        }

        Result<Page<HTUserInfoVO>> result = new Result<>();

        Page<HTPlatformUser> pageList = new Page<>(pageNo, pageSize);
        pageList = accountService.queryUserListByCertificateAuditStatus(pageList, user.getCertificateAuditStatus());

        Page<HTUserInfoVO> voPageList = new Page<>();
        voPageList.setCurrent(pageList.getCurrent());
        voPageList.setTotal(pageList.getTotal());
        voPageList.setPages(pageList.getPages());

        List<HTUserInfoVO> infoVOList = new ArrayList<>();
        List<HTPlatformUser> records = pageList.getRecords();
        records.forEach(record -> {
            HTAccountTypeEnum accountType = HTAccountTypeEnum.values()[record.getAccountType()];
            switch (accountType) {
                case FORUMS_EXPERT: {
                    HTForumsExpert forumsExpert = forumsExpertService.getById(record.getId());
                    HTUserInfoVO userInfoVO = SmartBeanUtil.copy(forumsExpert, HTUserInfoVO.class);
                    infoVOList.add(userInfoVO);
                }
                break;

                case MERCHANT: {
                    HTMerchant merchant = merchantService.getById(record.getId());
                    HTUserInfoVO userInfoVO = SmartBeanUtil.copy(merchant, HTUserInfoVO.class);
                    infoVOList.add(userInfoVO);
                }
                break;

                case EVALUATION_AGENCY: {
                    HTEvaluationAgency evaluationAgency = evaluationAgencyService.getById(record.getId());
                    HTUserInfoVO userInfoVO = SmartBeanUtil.copy(evaluationAgency, HTUserInfoVO.class);
                    infoVOList.add(userInfoVO);
                }
                break;

                case ALLIANCE: {
                    HTAlliance alliance = allianceService.getById(record.getId());
                    HTUserInfoVO userInfoVO = SmartBeanUtil.copy(alliance, HTUserInfoVO.class);
                    infoVOList.add(userInfoVO);
                }
                break;

                case ALLIANCE_MEMBER: {
                    HTAllianceMember allianceMember = allianceMemberService.getById(record.getId());
                    HTUserInfoVO userInfoVO = SmartBeanUtil.copy(allianceMember, HTUserInfoVO.class);
                    infoVOList.add(userInfoVO);
                }
                break;

                default:
                    break;
            }
        });

        voPageList.setRecords(infoVOList);

        result.setSuccess(true);
        result.setResult(voPageList);
        return result;
    }


    /**
     * @param request
     * @return
     */
    @PostMapping(value = "/getUserInfo")
    public Result<JSONObject> getUserInfo(HttpServletRequest request) {
        Result<JSONObject> result = new Result<>();

        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        String username = JwtUtil.getUsername(token);

        HTPlatformUser user = accountService.queryFrontendUserByUsername(username);
        HTUserInfoVO userInfo = accountService.getUserInfo(HTAccountTypeEnum.values()[user.getAccountType()], user.getId());

        boolean hasSetPassword = oConvertUtils.isNotEmpty(user.getPassword());
        userInfo.setHasSetPassword(hasSetPassword);

        JSONObject obj = new JSONObject();
        obj.put("userInfo", userInfo);
        result.setResult(obj);

        return result;
    }

    /**
     * @param request
     * @return
     */
    @PostMapping(value = "generateSalt")
    public Result<JSONObject> generateSalt(HttpServletRequest request) {
        Result<JSONObject> result = new Result<>();
        JSONObject obj = new JSONObject();
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (oConvertUtils.isNotEmpty(token)) {
            String username = JwtUtil.getUsername(token);
            HTPlatformUser user = accountService.queryFrontendUserByUsername(username);
            if (oConvertUtils.isNotEmpty(user)) {
                obj.put("oldSalt", user.getSalt());
            }
        }

        obj.put("salt", SaltUtil.salt());
        obj.put("timestamp", DateUtils.getTimestamp());
        result.setResult(obj);

        return result;
    }

    /**
     * @param request
     * @return
     */
    @PostMapping(value = "getSalt")
    public Result<JSONObject> getSalt(HttpServletRequest request, @Valid @RequestBody HTGetSaltDTO dto) {
        Result<JSONObject> result = new Result<>();

        String username = dto.getUsername();
        String phoneNumber = null;
        boolean matches = Pattern.matches(PHONE_REGEXP, username);
        if (matches) phoneNumber = username;

        HTPlatformUser user = accountService.queryFrontendUserByUsername(username);
        if (oConvertUtils.isEmpty(user)) {
            user = accountService.queryFrontendUserByPhoneNumber(phoneNumber);
        }

        if (oConvertUtils.isNotEmpty(user)) {
            String salt = user.getSalt();
            if (oConvertUtils.isNotEmpty(salt)) {
                JSONObject obj = new JSONObject();
                obj.put("salt", salt);
                obj.put("timestamp", DateUtils.getTimestamp());
                result.setResult(obj);
            } else {
                result.error500("账户未设置密码，请用手机验证码登录！");
            }
        } else {
            result.error500("用户不存在");
        }

        return result;
    }

    /**
     * @param dto
     * @return
     */
    @PostMapping(value = "updateUserInfo")
    public Result<JSONObject> updateUserInfo(HttpServletRequest request, @Valid @RequestBody HTUserUpdateDTO dto) {
        Result<JSONObject> result = new Result<>();
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        String originalUsername = JwtUtil.getUsername(token);
        String username = dto.getUsername();
        String phoneNumber = dto.getPhoneNumber();
        String email = dto.getEmail();

        boolean isAccountExist = accountService.validateAccountExistByMultipleFactor(username, phoneNumber, email);
        if (isAccountExist) {
            HTUserUpdateBO bo = SmartBeanUtil.copy(dto, HTUserUpdateBO.class);
            accountService.updateUserInfo(bo);

            assert originalUsername != null;
            if (!originalUsername.equals(username)) {
                HTPlatformUser user = accountService.queryFrontendUserByUsername(username);

                deleteUserCache(token, user.getId(), originalUsername);

                String password = user.getPassword();
                if (oConvertUtils.isEmpty(password)) {
                    password = UUIDGenerator.generate();
                }

                String newToken = addOrUpdateToken(user.getUsername(), password);

                JSONObject obj = new JSONObject();
                obj.put("token", newToken);
                result.setResult(obj);
            }


        } else {
            result.error500("用户不存在");
        }

        return result;
    }

    /**
     * @param dto
     * @return
     */
    @PostMapping(value = "upgradeUser")
    public Result<JSONObject> upgrade(HttpServletRequest request, @Valid @RequestBody HTAccountUpgradeDTO dto) {
        Result<JSONObject> result = new Result<>();
        String username = dto.getUsername();
        String phoneNumber = dto.getPhoneNumber();
        String email = dto.getEmail();

        boolean isAccountExist = accountService.validateAccountExistByMultipleFactor(username, phoneNumber, email);
        if (isAccountExist) {
            HTAccountUpgradeBO bo = SmartBeanUtil.copy(dto, HTAccountUpgradeBO.class);
            if (oConvertUtils.isNotEmpty(bo.getCertificate())) {
                HTCertificateSubmitBO certificateSubmitBO = SmartBeanUtil.copy(dto, HTCertificateSubmitBO.class);
                accountService.certificateSubmit(certificateSubmitBO);
            }

            boolean succeed = accountService.upgradeUser(bo);
            if (succeed) {
                result.setMessage("升级成功");
            } else {
                result.error500("升级失败，请稍后尝试");
            }
        } else {
            result.error500("用户不存在");
        }

        return result;
    }

    /**
     * @return 平台用户数据统计
     */
    @GetMapping(value = "getStatistics")
    public Result<JSONObject> getStatistics(HttpServletRequest request, String dayTime) {
        Result<JSONObject> result = new Result<>();
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (oConvertUtils.isNotEmpty(token)) {
            if (oConvertUtils.isEmpty(dayTime)) {
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                dayTime = DateUtils.date2Str(dateFormat);
            }
            HTUserStatisticsVO vo = accountService.queryStatistics(dayTime);
            result.setResult(JSONObject.parseObject(JSONObject.toJSONString(vo)));
        } else {
            result.error500("请先登录");
        }

        return result;
    }


}
